/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "common/hpm_common.h"
#include "common/hpm_errno.h"
#include "riscv/riscv_core.h"
#include "core/include/hpm6e00_regs_csr.h"
#include "core/include/hpm6e00_plic.h"
#include "core/include/hpm6e00_regs_base.h"

/*******************************************************************************
 * Static
 ******************************************************************************/
static void            *__g_p_irq_handler_arg[IRQ_NUM_MAX] = {NULL};
static pfn_irq_handler  __g_pfn_irq_handler[IRQ_NUM_MAX]   = {NULL};

/*******************************************************************************
 * Code
 ******************************************************************************/


/**
 * \brief Trap 中断处理函数
 */
void irq_trap_handler(void){
    long mcause  = read_csr(CSR_MCAUSE);
    long mepc    = read_csr(CSR_MEPC);
    long mstatus = read_csr(CSR_MSTATUS);

    (void)mcause;
#ifdef __riscv_32e
    __asm volatile("" : : : "t0", "a0", "a1", "a2", "a3");
#else
    __asm volatile("" : : : "a7", "a0", "a1", "a2", "a3");
#endif

    /* Restore CSR */
    write_csr(CSR_MSTATUS, mstatus);
    write_csr(CSR_MEPC,    mepc);
}

/**
 * \brief 中断通用回调函数
 */
void intc_gen_isr(uint32_t int_num){
    int                                   real_int_num;
    struct plic_threshold_claim_complete *p_claim_complete =
            (struct plic_threshold_claim_complete *)(HPM_PLIC_BASE + HPM_PLIC_THRESHOLD_OFFSET);

    asm volatile("" : : : "memory");

    /* 真正的中断号 */
    real_int_num = int_num & 0xFFFFUL;

    if (__g_pfn_irq_handler[real_int_num] != NULL) {
        /* 调用相应的中断回调函数*/
        __g_pfn_irq_handler[real_int_num](__g_p_irq_handler_arg[real_int_num]);
    }

    WRITE_REG32(p_claim_complete->claim_complete, int_num);

    asm volatile("" : : : "memory");
}

/**
 * \brief 中断控制器中断使能函数
 *
 * \param[in] target  中断模式
 * \param[in] irq_num 中断号
 */
void intc_irq_enable(uint32_t target, uint32_t irq_num){
    __plic_irq_enable(HPM_PLIC_BASE, target, irq_num);
}

/**
 * \brief 中断控制器中断禁能函数
 *
 * \param[in] target  中断模式
 * \param[in] irq_num 中断号
 */
void intc_irq_disable(uint32_t target, uint32_t irq_num){
    __plic_irq_disable(HPM_PLIC_BASE, target, irq_num);
}

/**
 * \brief 设置中断优先级
 *
 * \param[in] irq_num  中断号
 * \param[in] priority 中断优先级
 */
void intc_irq_priority_set(uint32_t irq_num, uint32_t priority){
    __plic_irq_priority_set(HPM_PLIC_BASE, irq_num, priority);
}

/**
 * \brief 中断处理函数注册
 *
 * \param[in] irq_num   要注册处理函数的中断号
 * \param[in] p_handler 中断处理函数
 * \param[in] p_arg     函数参数
 *
 * \retval 成功返回 0
 */
int intc_handler_register(uint32_t irq_num, pfn_irq_handler p_handler, void *p_arg){
    if ((p_handler == NULL) || (irq_num > IRQn_DEBUG_1)) {
        return -EINVAL;
    }

    __g_pfn_irq_handler[irq_num]   = p_handler;
    __g_p_irq_handler_arg[irq_num] = p_arg;

    return 0;
}
